#include "common/type/date_util.h"
#include "common/log/log.h"
#include <cstdio>
#include <cstring>

// 辅助函数：判断年份是否为闰年
bool DateUtil::is_leap_year(int year) {
  return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

// 辅助函数：获取指定年月的天数（考虑闰年）
int DateUtil::get_days_in_month(int year, int month) {
  // 平年各月天数（索引 0 对应 1 月，索引 1 对应 2 月...）
  static const int DAYS_PER_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  
  if (month < 1 || month > 12) {
    return 0;  // 非法月份返回 0（后续会判断为日期非法）
  }
  // 2 月特殊处理：闰年 29 天，平年 28 天
  if (month == 2 && is_leap_year(year)) {
    return 29;
  }
  return DAYS_PER_MONTH[month - 1];
}

//添加对日期类型和整数相加的函数
int DateUtil::add_days(int date, int days){
    // 解析日期
    int year = date / 10000;
    int month = (date % 10000) / 100;
    int day = date % 100;
    
    // 增加天数
    day += days;
    
    // 处理月份和年份进位
    while (true) {
        int daysInMonth = get_days_in_month(year, month);
        if (day <= daysInMonth) {
            break; // 无需进位
        }
        
        // 减去当前月的天数，进入下个月
        day -= daysInMonth;
        month++;
        
        // 处理年份进位
        if (month > 12) {
            month = 1;
            year++;
        }
    }
    
    // 组合成新的日期整数
    return year * 10000 + month * 100 + day;
}

// 将日期转换为从基准日期(1970年1月1日)开始的总天数
int DateUtil::date_to_total_days(int date) {
    int year = date / 10000;
    int month = (date % 10000) / 100;
    int day = date % 100;
    
    int totalDays = 0;
    
    // 累加完整年份的天数
    for (int y = 1970; y < year; y++) {
        totalDays += is_leap_year(y) ? 366 : 365;
    }
    
    // 累加完整月份的天数
    for (int m = 1; m < month; m++) {
        totalDays += get_days_in_month(year, m);
    }
    
    // 累加当月的天数
    totalDays += day;
    
    return totalDays;
}

// 计算两个日期之间的天数差
int DateUtil::get_date_difference(int date1, int date2) {
    int days1 = date_to_total_days(date1);
    int days2 = date_to_total_days(date2);
    
    // 返回天数差的绝对值
    return std::abs(days1 - days2);
}

// 解析日期字符串为基准天数
int32_t DateUtil::parse_date(const char *date_str) {
  // 步骤 1：校验输入字符串非空
  if (date_str == nullptr) {
    LOG_TRACE("Date string is null");
    return -1;
  }

  // 步骤 2：校验字符串格式（长度 + 分隔符）
  const int EXPECTED_LEN = 10;  // YYYY-MM-DD 固定 10 字符
  if (strlen(date_str) != EXPECTED_LEN) {
    LOG_TRACE("Invalid date string length: %zu (expected %d), str=%s", 
              strlen(date_str), EXPECTED_LEN, date_str);
    return -1;
  }
  // 校验分隔符（索引 4 和 7 必须是 '-'）
  if (date_str[4] != '-' || date_str[7] != '-') {
    LOG_TRACE("Invalid date separator: str=%s (expected YYYY-MM-DD)", date_str);
    return -1;
  }

  // 步骤 3：解析年、月、日为整数
  int year, month, day;
  // %4d：年份占 4 位，%2d：月份/日期占 2 位，确保解析正确
  int parse_count = sscanf(date_str, "%4d-%2d-%2d", &year, &month, &day);
  if (parse_count != 3) {  // 必须解析出 3 个整数才合法
    LOG_TRACE("Failed to parse date components: str=%s, parse_count=%d", 
              date_str, parse_count);
    return -1;
  }

  // 步骤 4：校验年、月、日合法性
  // 4.1 年份校验（1970~2038）
  if (year < MIN_YEAR || year > MAX_YEAR) {
    LOG_TRACE("Year out of range: %d (expected %d~%d)", 
              year, MIN_YEAR, MAX_YEAR);
    return -1;
  }
  // 4.2 月份校验（1~12）
  if (month < 1 || month > 12) {
    LOG_TRACE("Month out of range: %d (expected 1~12)", month);
    return -1;
  }
  // 4.3 日期校验（符合当月天数）
  int max_day = get_days_in_month(year, month);
  if (day < 1 || day > max_day) {
    LOG_TRACE("Day out of range: %d (max %d for %d-%02d)", 
              day, max_day, year, month);
    return -1;
  }

  // 步骤 5：计算从 1970-01-01 到目标日期的总天数
  int32_t total_days = 0;

  // 5.1 累加 1970 到目标年份前一年的总天数
  for (int y = BASE_YEAR; y < year; ++y) {
    total_days += is_leap_year(y) ? 366 : 365;
  }

  // 5.2 累加目标年份中，目标月份前一个月的总天数
  for (int m = 1; m < month; ++m) {
    total_days += get_days_in_month(year, m);
  }

  // 5.3 累加目标日期的天数（减 1：因为 1970-01-01 是第 0 天）
  total_days += (day - 1);

  // 步骤 6：返回最终的基准天数
  return total_days;
}

// 在date_util.cpp中添加format_date函数实现

/**
 * @brief 将基准天数转换为YYYY-MM-DD格式的日期字符串
 * @param date_days 从1970-01-01开始的天数偏移量
 * @return 格式化后的日期字符串，失败返回空字符串
 */
std::string DateUtil::format_date(int date_days) {
    // 1. 校验天数合法性
    if (date_days < MIN_YEAR_DAYS || date_days > MAX_YEAR_DAYS) {
        LOG_TRACE("Invalid date days: %d (valid range: %d-%d)",
                  date_days, MIN_YEAR_DAYS, MAX_YEAR_DAYS);
        return "";
    }

    // 2. 初始化计算变量
    int year = date_days / 10000;
    int month = (date_days % 10000) / 100;
    int day = date_days % 100;


    // 新增：校验日期合法性
    if (year < 1970 || year > 9999 ||   // 年份限制在 1970~9999
        month < 1 || month > 12 ||      // 月份限制在 1~12
        day < 1 || day > get_days_in_month(year,month)) {  // 日期限制在 1~31（可更严格，比如调用 get_days_in_month 校验）
      return ""; // 非法日期返回空字符串
    }

    // 6. 格式化输出为YYYY-MM-DD格式
    char date_str[20];  // 预留10个字符+终止符 但是为了兼容异常情况扩容为20字节
    snprintf(date_str, sizeof(date_str), "%04d-%02d-%02d", year, month, day);
    
    return std::string(date_str);
}
    